#include "ControlPanel.h"
#include <QTableView>
#include <QStandardItemModel>
#include <QVBoxLayout>
#include <QHeaderView>
#include <QGroupBox>
#include "../Settings/GameSettings.h"
#include <QCheckBox>
#include <QRadioButton>
#include <QCheckBox>
#include "../Utils/Tag.h"

ControlPanel::ControlPanel(QWidget *parent) :
    QWidget(parent)
{
    GameSettings::me()->setMostTopWnd(parent);

    QVBoxLayout *pVBox = new QVBoxLayout();
    pVBox->addWidget(createNetworkGroupBox());
    pVBox->addWidget(createComputerGroupBox());
    pVBox->addWidget(createPlayerGroupBox());
    pVBox->addWidget(createGameGroupBox());

    mItemsToDisableAtPlayingTime.append(mpModelPlayer->item(0,Game::Player1));
    mItemsToDisableAtPlayingTime.append(mpModelPlayer->item(0,Game::Player2));
    mItemsToDisableAtPlayingTime.append(mpModelGame->item(Game::DotsPerRow,0));
    mItemsToDisableAtPlayingTime.append(mpModelGame->item(Game::DotsPerColumn,0));
    mItemsToDisableAtPlayingTime.append(mpModelGame->item(Game::CellWidth,0));
    mItemsToDisableAtPlayingTime.append(mpModelGame->item(Game::CellHeight,0));
    mItemsToDisableAtPlayingTime.append(mpModelGame->item(Game::FieldMargin,0));

    setLayout(pVBox);
}

QGroupBox *ControlPanel::createNetworkGroupBox()
{
    QCheckBox *pBlockOthersWhilePlay = new QCheckBox(tr("Block others while play"));
    pBlockOthersWhilePlay->setChecked(GameSettings::me()->setting(Game::BlockOthersWhileNetPlay).value<bool>());

    QVBoxLayout *pNetlayout = new QVBoxLayout();
    pNetlayout->addWidget(pBlockOthersWhilePlay);

    QGroupBox *pGBNetSetting = new QGroupBox(tr("Net Play Settings"));
    pGBNetSetting->setLayout(pNetlayout);

    connect(pBlockOthersWhilePlay,SIGNAL(stateChanged(int)),SLOT(netPlayBlockStateChanged(int)));

    return pGBNetSetting;
}

QGroupBox *ControlPanel::createComputerGroupBox()
{
    Game::GameLevel level = Game::GameLevel(GameSettings::me()->setting(Game::PlayingLevel).value<int>());
    QRadioButton *pRBLearning = new QRadioButton("Learning");
    pRBLearning->setChecked(level == Game::Learning);
    pRBLearning->setUserData(ROLE_TAG,new UserIntData(int(Game::Learning)));
    QRadioButton *pRBPlaying = new QRadioButton("Playing");
    pRBPlaying->setUserData(ROLE_TAG,new UserIntData(int(Game::Playing)));
    pRBPlaying->setChecked(level == Game::Playing);

    QHBoxLayout *pHBoxLayout = new QHBoxLayout();            
    pHBoxLayout->addWidget(pRBLearning);
    pHBoxLayout->addWidget(pRBPlaying);

    mpGBPlayingWithComputer = new QGroupBox("Play with Computer");
    mpGBPlayingWithComputer->setToolTip("When it is checked, 'Computer' will be the 'Player2'.");
    mpGBPlayingWithComputer->setCheckable(true);
    mpGBPlayingWithComputer->setChecked(GameSettings::me()->playingWithComputer());
    mpGBPlayingWithComputer->setLayout(pHBoxLayout);
    connect(mpGBPlayingWithComputer,SIGNAL(toggled(bool)),SLOT(cbPlayingWithComputerChanged(bool)));
    connect(pRBLearning,SIGNAL(toggled(bool)),SLOT(gameLevelChanged(bool)));
    connect(pRBPlaying,SIGNAL(toggled(bool)),SLOT(gameLevelChanged(bool)));

    return mpGBPlayingWithComputer;
}

QGroupBox *ControlPanel::createPlayerGroupBox()
{
    GameSettings *pDI = GameSettings::me();

    mpModelPlayer = new QStandardItemModel(this);
    QStringList lbsHorz,lbsVert;
    lbsVert << "Name" << "Color";
    lbsHorz << "Player 1"<< "Player 2";
    mpModelPlayer->setHorizontalHeaderLabels(lbsHorz);
    mpModelPlayer->setVerticalHeaderLabels(lbsVert);
    QItemSelectionModel *pSelectionModel = new QItemSelectionModel(mpModelPlayer);

    mpModelPlayer->setData(mpModelPlayer->index(0,Game::Player1,QModelIndex()),pDI->playerName(Game::Player1));
    mpModelPlayer->setData(mpModelPlayer->index(0,Game::Player2,QModelIndex()),pDI->playerName(Game::Player2));
    mpModelPlayer->item(0,Game::Player1)->setData(pDI->playerColor(Game::Player1),Qt::ForegroundRole);
    mpModelPlayer->item(0,Game::Player2)->setData(pDI->playerColor(Game::Player2),Qt::ForegroundRole);
    mpModelPlayer->item(0,Game::Player1)->setData(Game::Player1,ROLE_TAG);
    mpModelPlayer->item(0,Game::Player2)->setData(Game::Player2,ROLE_TAG);

    mpModelPlayer->setData(mpModelPlayer->index(1,0,QModelIndex()),pDI->playerColor(Game::Player1),Qt::DecorationRole);
    mpModelPlayer->setData(mpModelPlayer->index(1,1,QModelIndex()),pDI->playerColor(Game::Player2),Qt::DecorationRole);
    mpModelPlayer->item(1,0)->setEditable(false);
    mpModelPlayer->item(1,1)->setEditable(false);
    mpModelPlayer->item(1,Game::Player1)->setData(Game::Player1,ROLE_TAG);
    mpModelPlayer->item(1,Game::Player2)->setData(Game::Player2,ROLE_TAG);

    QTableView *mpTableView = new QTableView(this);
    mpTableView->setModel(mpModelPlayer);
    mpTableView->setSelectionModel(pSelectionModel);
    mpTableView->horizontalHeader()->setStretchLastSection(true);


    QVBoxLayout *pPlayerBox = new QVBoxLayout();
    pPlayerBox->addWidget(mpTableView);
    QGroupBox *pGBPlayer = new QGroupBox("Player Settings");
    pGBPlayer->setLayout(pPlayerBox);
    pGBPlayer->setFixedHeight(120);

    connect(mpTableView,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(playerItemDoubleClicked(QModelIndex)));
    connect(mpModelPlayer,SIGNAL(itemChanged(QStandardItem*)),SLOT(playerItemChanged(QStandardItem*)));

    return pGBPlayer;
}

QGroupBox *ControlPanel::createGameGroupBox()
{    
    mpModelGame = new QStandardItemModel(this);
    QStringList lbsHorz,lbsVert;
    lbsVert << "Dots in Row" << "Dots in Col" << "Cell Width" << "Cell Height" << "Dot Radii" << "Pen Width" << "Margin"
            << "BG Color" << "Field Color" << "Normal Dot" << "Used Dot"
            << "Selected Dot" << "Usable Dot" << "Moving Point" << "Progress Color";
    lbsHorz << "Information";

    mpModelGame->setVerticalHeaderLabels(lbsVert);
    mpModelGame->setHorizontalHeaderLabels(lbsHorz);
    QItemSelectionModel *pSelectionModel = new QItemSelectionModel(mpModelGame);

    initGameModelRow(Game::DotsPerRow,false);
    initGameModelRow(Game::DotsPerColumn,false);
    initGameModelRow(Game::CellWidth,false);
    initGameModelRow(Game::CellHeight,false);
    initGameModelRow(Game::DotRadii,false);
    initGameModelRow(Game::PenWidth,false);
    initGameModelRow(Game::FieldMargin,false);

    initGameModelRow(Game::BGColor,true);
    initGameModelRow(Game::FieldColor,true);
    initGameModelRow(Game::DotNormalColor,true);
    initGameModelRow(Game::DotUsedColor,true);
    initGameModelRow(Game::DotSelectedColor,true);
    initGameModelRow(Game::DotSelectableColor,true);
    initGameModelRow(Game::PointMovable,true);
    initGameModelRow(Game::ProgressBar,true);

    QTableView *mpTableView = new QTableView(this);
    mpSpinboxDelegate = new SpinBoxDelegate(this);
    mpTableView->setItemDelegate(mpSpinboxDelegate);
    mpTableView->setModel(mpModelGame);
    mpTableView->setSelectionModel(pSelectionModel);
    mpTableView->horizontalHeader()->setStretchLastSection(true);

    QVBoxLayout *pGameBox = new QVBoxLayout();
    pGameBox->addWidget(mpTableView);
    QGroupBox *pGBGame = new QGroupBox("Game Settings");
    pGBGame->setLayout(pGameBox);

    connect(mpTableView,SIGNAL(doubleClicked(QModelIndex)),this,SLOT(gameItemDoubleClicked(QModelIndex)));
    connect(mpModelGame,SIGNAL(itemChanged(QStandardItem*)),SLOT(gameItemChanged(QStandardItem*)));

    return pGBGame;
}

void ControlPanel::initGameModelRow(int nParam,bool bColor)
{
    if(bColor){
        Game::Setting param = Game::Setting(nParam);
        mpModelGame->setData(mpModelGame->index(param,0,QModelIndex()),GameSettings::me()->setting(param).value<QColor>(),Qt::DecorationRole);
        mpModelGame->item(param,0)->setData(param,ROLE_TAG);
        mpModelGame->item(param,0)->setEditable(false);
    }
    else{
        Game::Setting param = Game::Setting(nParam);
        mpModelGame->setData(mpModelGame->index(param,0,QModelIndex()),GameSettings::me()->setting(param).value<uint>());
        mpModelGame->item(param,0)->setData(param,ROLE_TAG);

    }
}

void ControlPanel::playerItemDoubleClicked(const QModelIndex &index)
{
    if(showColorDlg(mpModelPlayer->itemFromIndex(index))){
        mpModelPlayer->item(0,Game::Player1)->setData(mpModelPlayer->item(1,Game::Player1)->data(Qt::DecorationRole).value<QColor>(),Qt::ForegroundRole);
        mpModelPlayer->item(0,Game::Player2)->setData(mpModelPlayer->item(1,Game::Player2)->data(Qt::DecorationRole).value<QColor>(),Qt::ForegroundRole);

        GameSettings::me()->setPlayerColor(Game::Player1,mpModelPlayer->item(1,Game::Player1)->data(Qt::DecorationRole).value<QColor>());
        GameSettings::me()->setPlayerColor(Game::Player2,mpModelPlayer->item(1,Game::Player2)->data(Qt::DecorationRole).value<QColor>());
    }
}

void ControlPanel::gameItemDoubleClicked(const QModelIndex &index)
{
    showColorDlg(mpModelGame->itemFromIndex(index));
}

bool ControlPanel::showColorDlg(QStandardItem *pItem)
{
    if(pItem){
        QVariant value = pItem->data(Qt::DecorationRole);

        if(value.isValid()){
            QColor color = mColorDlg.getColor(value.value<QColor>(),this);

            if(color.isValid()){
                pItem->setData(color,Qt::DecorationRole);

                return true;
            }
        }
    }

    return false;
}

void ControlPanel::playerItemChanged(QStandardItem *item)
{
    QVariant value = item->data(Qt::EditRole);

    if(value.isValid()){
        if(value.toString().isEmpty()){
            item->setData(GameSettings::me()->playerName(Game::Player(item->column())),Qt::EditRole);
        }
        else{
            GameSettings::me()->setPlayerName(Game::Player(item->column()),value.toString());
        }
    }
}

void ControlPanel::gameItemChanged(QStandardItem *item)
{
    Qt::ItemDataRole role = item->row() <= Game::FieldMargin ? Qt::EditRole : Qt::DecorationRole;
    QVariant value = item->data(role);

    if(value.isValid()){
        GameSettings::me()->setSetting(Game::Setting(item->row()),value);
    }
}

void ControlPanel::cbPlayingWithComputerChanged(bool bChangedState)
{
    GameSettings::me()->setPlayWithComputer(bChangedState);
}

void ControlPanel::gameStarted()
{
    setEnableItemsAtPlayingTime(false);
}

void ControlPanel::gameFinished(Game::Player player)
{
    setEnableItemsAtPlayingTime(true);
}

void ControlPanel::gameCanceled()
{
    setEnableItemsAtPlayingTime(true);
}

void ControlPanel::setEnableItemsAtPlayingTime(bool bEnable)
{
    for(int i = 0; i < mItemsToDisableAtPlayingTime.count(); i++){
        mItemsToDisableAtPlayingTime.at(i)->setEditable(bEnable);
    }

    mpGBPlayingWithComputer->setEnabled(bEnable);
}

bool ControlPanel::aMomentBeforeClosing()
{
    GameSettings::me()->setSetting(Game::WindowPosition,GameSettings::me()->mostTopWnd()->pos());
    GameSettings::me()->setSetting(Game::WindowSize,GameSettings::me()->mostTopWnd()->size());
    return true; // true to ok, false to request a so that application is not get closed
}

void ControlPanel::gameLevelChanged(bool bChecked)
{
    if(bChecked){
        QRadioButton *pRB = reinterpret_cast<QRadioButton*>(sender());
        UserIntData *pData = dynamic_cast<UserIntData*>(pRB->userData(ROLE_TAG));
        GameSettings::me()->setSetting(Game::PlayingLevel,pData->data());
    }
}

void ControlPanel::networkGameStartingParameterRequest(int nDotsPerRow, int nDotsPerColumn, QString playerName, QColor color)
{
    GameSettings::me()->setSetting(Game::DotsPerRow,nDotsPerRow);
    GameSettings::me()->setSetting(Game::DotsPerColumn,nDotsPerColumn);
    mpModelGame->item(int(Game::DotsPerRow),0)->setData(nDotsPerRow,Qt::EditRole);
    mpModelGame->item(int(Game::DotsPerColumn),0)->setData(nDotsPerColumn,Qt::EditRole);
    networkGamePlayingViewInfoChanged(playerName,color);
    mpGBPlayingWithComputer->setChecked(false);
    GameSettings::me()->setPlayWithComputer(false);
}

void ControlPanel::networkGamePlayingViewInfoChanged(QString playerName, QColor color)
{
    GameSettings::me()->setPlayerName(Game::Player2,playerName);
    GameSettings::me()->setPlayerColor(Game::Player2,color);
    mpModelPlayer->item(0,Game::Player2)->setData(playerName,Qt::EditRole);
    mpModelPlayer->item(1,Game::Player2)->setData(color,Qt::DecorationRole);
}

void ControlPanel::netPlayBlockStateChanged(int nState)
{
    GameSettings::me()->setSetting(Game::BlockOthersWhileNetPlay,nState == Qt::Checked ? true : false);
}
